package org.xx.armory.db;

/**
 * 将一条记录映射到实体对象的映射器。
 *
 * @param <T>
 *         实体对象的类型。
 * @author Haart
 */
@FunctionalInterface
public interface Mapper<T> {
    /**
     * 将一条记录的第一列的值映射为对象。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getObject(int)
     */
    static Object toObject(
            DbRow row
    ) {
        return row.getObject(0);
    }

    /**
     * 将一条记录的第一列的值映射为字符串。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的字符串对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getString(int)
     */
    static String toStr(
            DbRow row
    ) {
        return row.getString(0);
    }

    /**
     * 将一条记录的第一列的值映射为Long。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Long对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getLong(int)
     */
    static Long toLong(
            DbRow row
    ) {
        return row.getLong(0);
    }

    /**
     * 将一条记录的第一列的值映射为Integer。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Integer对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getInteger(int)
     */
    static Integer toInt(
            DbRow row
    ) {
        return row.getInteger(0);
    }

    /**
     * 将一条记录的第一列的值映射为Double。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Double对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getDouble(int)
     */
    static Double toDouble(
            DbRow row
    ) {
        return row.getDouble(0);
    }

    /**
     * 将一条记录的第一列的值映射为BigDecimal。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的字符串对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getDecimal(int)
     */
    static java.math.BigDecimal toDecimal(
            DbRow row
    ) {
        return row.getDecimal(0);
    }

    /**
     * 将一条记录的第一列的值映射为Date。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Date对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getDate(int)
     */
    static java.util.Date toDate(
            DbRow row
    ) {
        return row.getDate(0);
    }

    /**
     * 将一条记录的第一列的值映射为Boolean。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Boolean对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getBoolean(int)
     */
    static Boolean toBool(
            DbRow row
    ) {
        return row.getBoolean(0);
    }

    /**
     * 将一条记录的第一列的值映射为字节数组。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的字节数组对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getBinary(int)
     */
    static byte[] toBinary(
            DbRow row
    ) {
        return row.getBinary(0);
    }

    /**
     * 将一条记录的第一列的值映射为Object数组。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据记录的第一列生成的Object数组对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see DbRow#getObject(int)
     */
    static Object[] toObjects(
            DbRow row
    ) {
        Object[] ret = new Object[row.length()];

        for (int i = 0; i < ret.length; ++i) {
            ret[i] = row.getObject(i);
        }

        return ret;
    }

    /**
     * 该记录能否产生新的映射实体对象。用于在分页查询时判断是否继续映射，以及是否可以从映射中获取新的结果。
     *
     * @param row
     *         数据库中的一条记录。
     * @return 如果对该记录进行映射，能否得到一个新的实体对象，那么返回{@code true}，否则返回{@code false}。
     * @see #execute(DbRow)
     */
    default boolean canGetNewResult(
            DbRow row
    ) {
        return row.hasData();
    }

    /**
     * 对记录进行映射，并得到当前的映射结果。
     * <p><strong>返回的映射结果可能不是当前记录产生的！</strong></p>
     *
     * @param row
     *         数据库中的一条记录。
     * @return 根据一条记录生成的实体对象, 如果无法映射则返回{@code null}。
     * @throws IllegalArgumentException
     *         如果参数{@code row}是{@code null}。
     * @see #canGetNewResult(DbRow)
     */
    T execute(
            DbRow row
    );
}
